; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+mve.fp -float-abi=hard -verify-machineinstrs %s -o - | FileCheck %s

define float @add_f32(<8 x float> %a, <4 x float> %b) {
; CHECK-LABEL: add_f32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vadd.f32 q0, q0, q1
; CHECK-NEXT:    vadd.f32 q0, q0, q2
; CHECK-NEXT:    vadd.f32 s2, s2, s3
; CHECK-NEXT:    vadd.f32 s0, s0, s1
; CHECK-NEXT:    vadd.f32 s0, s0, s2
; CHECK-NEXT:    bx lr
  %r1 = call fast float @llvm.vector.reduce.fadd.f32.v8f32(float -0.0, <8 x float> %a)
  %r2 = call fast float @llvm.vector.reduce.fadd.f32.v4f32(float -0.0, <4 x float> %b)
  %r = fadd fast float %r1, %r2
  ret float %r
}

define float @fmul_f32(<8 x float> %a, <4 x float> %b) {
; CHECK-LABEL: fmul_f32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vmul.f32 q0, q0, q1
; CHECK-NEXT:    vmul.f32 q0, q0, q2
; CHECK-NEXT:    vmul.f32 s2, s2, s3
; CHECK-NEXT:    vmul.f32 s0, s0, s1
; CHECK-NEXT:    vmul.f32 s0, s0, s2
; CHECK-NEXT:    bx lr
  %r1 = call fast float @llvm.vector.reduce.fmul.f32.v8f32(float 1.0, <8 x float> %a)
  %r2 = call fast float @llvm.vector.reduce.fmul.f32.v4f32(float 1.0, <4 x float> %b)
  %r = fmul fast float %r1, %r2
  ret float %r
}

define float @fmin_f32(<8 x float> %a, <4 x float> %b) {
; CHECK-LABEL: fmin_f32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vminnm.f32 q0, q0, q1
; CHECK-NEXT:    vminnm.f32 s4, s8, s9
; CHECK-NEXT:    vminnm.f32 s2, s2, s3
; CHECK-NEXT:    vminnm.f32 s0, s0, s1
; CHECK-NEXT:    vminnm.f32 s0, s0, s2
; CHECK-NEXT:    vminnm.f32 s2, s10, s11
; CHECK-NEXT:    vminnm.f32 s2, s4, s2
; CHECK-NEXT:    vminnm.f32 s0, s0, s2
; CHECK-NEXT:    bx lr
  %r1 = call fast float @llvm.vector.reduce.fmin.v8f32(<8 x float> %a)
  %r2 = call fast float @llvm.vector.reduce.fmin.v4f32(<4 x float> %b)
  %r = call float @llvm.minnum.f32(float %r1, float %r2)
  ret float %r
}

define float @fmax_f32(<8 x float> %a, <4 x float> %b) {
; CHECK-LABEL: fmax_f32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vmaxnm.f32 q0, q0, q1
; CHECK-NEXT:    vmaxnm.f32 s4, s8, s9
; CHECK-NEXT:    vmaxnm.f32 s2, s2, s3
; CHECK-NEXT:    vmaxnm.f32 s0, s0, s1
; CHECK-NEXT:    vmaxnm.f32 s0, s0, s2
; CHECK-NEXT:    vmaxnm.f32 s2, s10, s11
; CHECK-NEXT:    vmaxnm.f32 s2, s4, s2
; CHECK-NEXT:    vmaxnm.f32 s0, s0, s2
; CHECK-NEXT:    bx lr
  %r1 = call fast float @llvm.vector.reduce.fmax.v8f32(<8 x float> %a)
  %r2 = call fast float @llvm.vector.reduce.fmax.v4f32(<4 x float> %b)
  %r = call float @llvm.maxnum.f32(float %r1, float %r2)
  ret float %r
}


define i32 @add_i32(<8 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: add_i32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vaddv.u32 r0, q1
; CHECK-NEXT:    vaddva.u32 r0, q0
; CHECK-NEXT:    vaddva.u32 r0, q2
; CHECK-NEXT:    bx lr
  %r1 = call i32 @llvm.vector.reduce.add.i32.v8i32(<8 x i32> %a)
  %r2 = call i32 @llvm.vector.reduce.add.i32.v4i32(<4 x i32> %b)
  %r = add i32 %r1, %r2
  ret i32 %r
}

define i16 @add_ext_i16(<16 x i8> %a, <16 x i8> %b) {
; CHECK-LABEL: add_ext_i16:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vaddv.u8 r0, q1
; CHECK-NEXT:    vaddva.u8 r0, q0
; CHECK-NEXT:    bx lr
  %ae = zext <16 x i8> %a to <16 x i16>
  %be = zext <16 x i8> %b to <16 x i16>
  %r1 = call i16 @llvm.vector.reduce.add.i16.v16i16(<16 x i16> %ae)
  %r2 = call i16 @llvm.vector.reduce.add.i16.v16i16(<16 x i16> %be)
  %r = add i16 %r1, %r2
  ret i16 %r
}

define i16 @add_ext_v32i16(<32 x i8> %a, <16 x i8> %b) {
; CHECK-LABEL: add_ext_v32i16:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    .pad #32
; CHECK-NEXT:    sub sp, #32
; CHECK-NEXT:    mov r1, sp
; CHECK-NEXT:    add r2, sp, #16
; CHECK-NEXT:    vstrw.32 q0, [r1]
; CHECK-NEXT:    vstrw.32 q1, [r2]
; CHECK-NEXT:    vldrb.u16 q1, [r2]
; CHECK-NEXT:    vldrb.u16 q0, [r1]
; CHECK-NEXT:    vaddv.u16 r0, q1
; CHECK-NEXT:    vaddva.u16 r0, q0
; CHECK-NEXT:    vldrb.u16 q0, [r1, #8]
; CHECK-NEXT:    vaddva.u16 r0, q0
; CHECK-NEXT:    vldrb.u16 q0, [r2, #8]
; CHECK-NEXT:    vaddva.u16 r0, q0
; CHECK-NEXT:    vaddva.u8 r0, q2
; CHECK-NEXT:    add sp, #32
; CHECK-NEXT:    bx lr
  %ae = zext <32 x i8> %a to <32 x i16>
  %be = zext <16 x i8> %b to <16 x i16>
  %r1 = call i16 @llvm.vector.reduce.add.i16.v32i16(<32 x i16> %ae)
  %r2 = call i16 @llvm.vector.reduce.add.i16.v16i16(<16 x i16> %be)
  %r = add i16 %r1, %r2
  ret i16 %r
}

define i32 @mul_i32(<8 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: mul_i32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vmul.i32 q0, q0, q1
; CHECK-NEXT:    vmul.i32 q0, q0, q2
; CHECK-NEXT:    vmov r0, r1, d1
; CHECK-NEXT:    vmov r2, r3, d0
; CHECK-NEXT:    muls r0, r1, r0
; CHECK-NEXT:    mul r1, r2, r3
; CHECK-NEXT:    muls r0, r1, r0
; CHECK-NEXT:    bx lr
  %r1 = call i32 @llvm.vector.reduce.mul.i32.v8i32(<8 x i32> %a)
  %r2 = call i32 @llvm.vector.reduce.mul.i32.v4i32(<4 x i32> %b)
  %r = mul i32 %r1, %r2
  ret i32 %r
}

define i32 @and_i32(<8 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: and_i32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vand q0, q0, q1
; CHECK-NEXT:    vand q0, q0, q2
; CHECK-NEXT:    vmov r0, r1, d1
; CHECK-NEXT:    vmov r2, r3, d0
; CHECK-NEXT:    ands r0, r1
; CHECK-NEXT:    and.w r1, r2, r3
; CHECK-NEXT:    ands r0, r1
; CHECK-NEXT:    bx lr
  %r1 = call i32 @llvm.vector.reduce.and.i32.v8i32(<8 x i32> %a)
  %r2 = call i32 @llvm.vector.reduce.and.i32.v4i32(<4 x i32> %b)
  %r = and i32 %r1, %r2
  ret i32 %r
}

define i32 @or_i32(<8 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: or_i32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vorr q0, q0, q1
; CHECK-NEXT:    vorr q0, q0, q2
; CHECK-NEXT:    vmov r0, r1, d1
; CHECK-NEXT:    vmov r2, r3, d0
; CHECK-NEXT:    orrs r0, r1
; CHECK-NEXT:    orr.w r1, r2, r3
; CHECK-NEXT:    orrs r0, r1
; CHECK-NEXT:    bx lr
  %r1 = call i32 @llvm.vector.reduce.or.i32.v8i32(<8 x i32> %a)
  %r2 = call i32 @llvm.vector.reduce.or.i32.v4i32(<4 x i32> %b)
  %r = or i32 %r1, %r2
  ret i32 %r
}

define i32 @xor_i32(<8 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: xor_i32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    veor q0, q0, q1
; CHECK-NEXT:    veor q0, q0, q2
; CHECK-NEXT:    vmov r0, r1, d1
; CHECK-NEXT:    vmov r2, r3, d0
; CHECK-NEXT:    eors r0, r1
; CHECK-NEXT:    eor.w r1, r2, r3
; CHECK-NEXT:    eors r0, r1
; CHECK-NEXT:    bx lr
  %r1 = call i32 @llvm.vector.reduce.xor.i32.v8i32(<8 x i32> %a)
  %r2 = call i32 @llvm.vector.reduce.xor.i32.v4i32(<4 x i32> %b)
  %r = xor i32 %r1, %r2
  ret i32 %r
}

define i32 @umin_i32(<8 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: umin_i32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vmin.u32 q0, q0, q1
; CHECK-NEXT:    mov.w r0, #-1
; CHECK-NEXT:    vmin.u32 q0, q0, q2
; CHECK-NEXT:    vminv.u32 r0, q0
; CHECK-NEXT:    bx lr
  %r1 = call i32 @llvm.vector.reduce.umin.i32.v8i32(<8 x i32> %a)
  %r2 = call i32 @llvm.vector.reduce.umin.i32.v4i32(<4 x i32> %b)
  %r = call i32 @llvm.umin.i32(i32 %r1, i32 %r2)
  ret i32 %r
}

define i32 @umax_i32(<8 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: umax_i32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vmax.u32 q0, q0, q1
; CHECK-NEXT:    movs r0, #0
; CHECK-NEXT:    vmax.u32 q0, q0, q2
; CHECK-NEXT:    vmaxv.u32 r0, q0
; CHECK-NEXT:    bx lr
  %r1 = call i32 @llvm.vector.reduce.umax.i32.v8i32(<8 x i32> %a)
  %r2 = call i32 @llvm.vector.reduce.umax.i32.v4i32(<4 x i32> %b)
  %r = call i32 @llvm.umax.i32(i32 %r1, i32 %r2)
  ret i32 %r
}

define i32 @smin_i32(<8 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: smin_i32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vmin.s32 q0, q0, q1
; CHECK-NEXT:    mvn r0, #-2147483648
; CHECK-NEXT:    vmin.s32 q0, q0, q2
; CHECK-NEXT:    vminv.s32 r0, q0
; CHECK-NEXT:    bx lr
  %r1 = call i32 @llvm.vector.reduce.smin.i32.v8i32(<8 x i32> %a)
  %r2 = call i32 @llvm.vector.reduce.smin.i32.v4i32(<4 x i32> %b)
  %r = call i32 @llvm.smin.i32(i32 %r1, i32 %r2)
  ret i32 %r
}

define i32 @smax_i32(<8 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: smax_i32:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    vmax.s32 q0, q0, q1
; CHECK-NEXT:    mov.w r0, #-2147483648
; CHECK-NEXT:    vmax.s32 q0, q0, q2
; CHECK-NEXT:    vmaxv.s32 r0, q0
; CHECK-NEXT:    bx lr
  %r1 = call i32 @llvm.vector.reduce.smax.i32.v8i32(<8 x i32> %a)
  %r2 = call i32 @llvm.vector.reduce.smax.i32.v4i32(<4 x i32> %b)
  %r = call i32 @llvm.smax.i32(i32 %r1, i32 %r2)
  ret i32 %r
}

declare float @llvm.vector.reduce.fadd.f32.v8f32(float, <8 x float>)
declare float @llvm.vector.reduce.fadd.f32.v4f32(float, <4 x float>)
declare float @llvm.vector.reduce.fmul.f32.v8f32(float, <8 x float>)
declare float @llvm.vector.reduce.fmul.f32.v4f32(float, <4 x float>)
declare float @llvm.vector.reduce.fmin.v8f32(<8 x float>)
declare float @llvm.vector.reduce.fmin.v4f32(<4 x float>)
declare float @llvm.vector.reduce.fmax.v8f32(<8 x float>)
declare float @llvm.vector.reduce.fmax.v4f32(<4 x float>)
declare i32 @llvm.vector.reduce.add.i32.v8i32(<8 x i32>)
declare i32 @llvm.vector.reduce.add.i32.v4i32(<4 x i32>)
declare i16 @llvm.vector.reduce.add.i16.v32i16(<32 x i16>)
declare i16 @llvm.vector.reduce.add.i16.v16i16(<16 x i16>)
declare i32 @llvm.vector.reduce.mul.i32.v8i32(<8 x i32>)
declare i32 @llvm.vector.reduce.mul.i32.v4i32(<4 x i32>)
declare i32 @llvm.vector.reduce.and.i32.v8i32(<8 x i32>)
declare i32 @llvm.vector.reduce.and.i32.v4i32(<4 x i32>)
declare i32 @llvm.vector.reduce.or.i32.v8i32(<8 x i32>)
declare i32 @llvm.vector.reduce.or.i32.v4i32(<4 x i32>)
declare i32 @llvm.vector.reduce.xor.i32.v8i32(<8 x i32>)
declare i32 @llvm.vector.reduce.xor.i32.v4i32(<4 x i32>)
declare i32 @llvm.vector.reduce.umin.i32.v8i32(<8 x i32>)
declare i32 @llvm.vector.reduce.umin.i32.v4i32(<4 x i32>)
declare i32 @llvm.vector.reduce.umax.i32.v8i32(<8 x i32>)
declare i32 @llvm.vector.reduce.umax.i32.v4i32(<4 x i32>)
declare i32 @llvm.vector.reduce.smin.i32.v8i32(<8 x i32>)
declare i32 @llvm.vector.reduce.smin.i32.v4i32(<4 x i32>)
declare i32 @llvm.vector.reduce.smax.i32.v8i32(<8 x i32>)
declare i32 @llvm.vector.reduce.smax.i32.v4i32(<4 x i32>)
declare float @llvm.minnum.f32(float, float)
declare float @llvm.maxnum.f32(float, float)
declare i32 @llvm.umin.i32(i32, i32)
declare i32 @llvm.umax.i32(i32, i32)
declare i32 @llvm.smin.i32(i32, i32)
declare i32 @llvm.smax.i32(i32, i32)
